
#include <assert.h>

#ifdef KOGI_ENABLE_ITEM_TYPE_SAFETY
#define KOGI_ITEM_FROM_TEMPLATE_(from, data_member, item_type) \
        struct kogi_item item = { .data.u64 = 0 }; \
        item.dat ## data_member = from; \
        item.type = KOGI_ITEM_##item_type; \
        return item
#else
#define KOGI_ITEM_FROM_TEMPLATE_(data_member, item_type) \
        struct kogi_item item = { .data.u64 = 0 }; \
        item.dat ## data_member = x; \
        return item
#endif

static inline struct kogi_item kogi_from_char(char x)                   { KOGI_ITEM_FROM_TEMPLATE_(x, a.c, CHAR); }
static inline struct kogi_item kogi_from_cstr(char const* x)            { KOGI_ITEM_FROM_TEMPLATE_(x, a.cstr, CSTRING); }
static inline struct kogi_item kogi_from_double(double x)               { KOGI_ITEM_FROM_TEMPLATE_(x, a.d, DOUBLE); }
static inline struct kogi_item kogi_from_float(float x)                 { KOGI_ITEM_FROM_TEMPLATE_(x, a.f, FLOAT); }
static inline struct kogi_item kogi_from_int(int x)                     { KOGI_ITEM_FROM_TEMPLATE_(x, a.i, INT); }
static inline struct kogi_item kogi_from_int8(int8_t x)                 { KOGI_ITEM_FROM_TEMPLATE_(x, a.i8, INT8); }
static inline struct kogi_item kogi_from_int16(int16_t x)               { KOGI_ITEM_FROM_TEMPLATE_(x, a.i16, INT16); }
static inline struct kogi_item kogi_from_ullong(unsigned long long x)   { KOGI_ITEM_FROM_TEMPLATE_(x, a.ull, ULLONG); }

#undef KOGI_ITEM_FROM_TEMPLATE_


#ifdef KOGI_ENABLE_ITEM_TYPE_SAFETY
#define KOGI_ITEM_TO_TEMPLATE_(item, data_member, item_type) \
        assert(KOGI_ITEM_ ## item_type == item.type); \
        return item.dat ## data_member
#else
#define KOGI_ITEM_TO_TEMPLATE_(item, data_member, item_type) \
        return item.dat ## data_member
#endif

static inline char kogi_to_char(struct kogi_item item)                  { KOGI_ITEM_TO_TEMPLATE_(item, a.c, CHAR); }
static inline char const* kogi_to_cstr(struct kogi_item item)           { KOGI_ITEM_TO_TEMPLATE_(item, a.cstr, CSTRING); }
static inline double kogi_to_double(struct kogi_item item)              { KOGI_ITEM_TO_TEMPLATE_(item, a.d, DOUBLE); }
static inline float kogi_to_float(struct kogi_item item)                { KOGI_ITEM_TO_TEMPLATE_(item, a.f, FLOAT); }
static inline int kogi_to_int(struct kogi_item item)                    { KOGI_ITEM_TO_TEMPLATE_(item, a.i, INT); }
static inline int8_t kogi_to_int8(struct kogi_item item)                { KOGI_ITEM_TO_TEMPLATE_(item, a.i8, INT8); }
static inline int16_t kogi_to_int16(struct kogi_item item)              { KOGI_ITEM_TO_TEMPLATE_(item, a.i16, INT16); }
static inline unsigned long long kogi_to_ullong(struct kogi_item item)  { KOGI_ITEM_TO_TEMPLATE_(item, a.ull, ULLONG); }

#undef KOGI_ITEM_TO_TEMPLATE_

